#include "STrainer.h"
#include "resource.h"
#include "MsgWinApiLastError.h"
#include "EnableDebugPrivileges.h"
#include "ICheat.h"
#include <iostream>

namespace TLib
{

	TRAINER_LIB_API STrainer::STrainer(
		const std::string& gameTitle,
		const std::string& trainerTitle,
		unsigned int cxWnd,
		unsigned int cyWnd,
		int iconId,
		int wndBackBmpId)
		: tr_wndClassName("trainerlibwnd")
	{
		this->g_title          = gameTitle;
		this->tr_wndTitle      = trainerTitle;
		this->tr_cyWnd         = cyWnd;
		this->tr_cxWnd         = cxWnd;
		this->tr_wndIconId     = iconId;
		this->tr_wndBackBmpId  = wndBackBmpId;
		tr_hInstance           = (HINSTANCE)GetModuleHandle(NULL);
		
		EnableDebugPrivileges();



		WNDCLASSEX wc;
		HBITMAP  hBitmap;


		if (tr_wndBackBmpId != -1)
		{
			hBitmap = LoadBitmap(tr_hInstance, MAKEINTRESOURCE(tr_wndBackBmpId));
			hBrush = CreatePatternBrush(hBitmap);
			DeleteObject(hBitmap);
		}

		// Clear out the window class for use
		ZeroMemory(&wc, sizeof(WNDCLASSEX));

		// Fill in the struct with the needed information
		wc.cbSize        = sizeof(WNDCLASSEX);
		wc.style         = CS_HREDRAW | CS_VREDRAW;
		wc.lpfnWndProc   = (WNDPROC)tr_wndProc;
		wc.hInstance     = tr_hInstance;
		wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
		if (tr_wndBackBmpId != -1)
			wc.hbrBackground = hBrush;
		else
			wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
		wc.lpszClassName = tr_wndClassName.c_str();
		if (tr_wndIconId != -1)
			wc.hIcon     = LoadIcon (tr_hInstance, MAKEINTRESOURCE (tr_wndIconId));

		// Register the main window class
		RegisterClassEx(&wc);

		// Create the window and use the result as the handle
		tr_hWnd = CreateWindowEx(NULL,
			tr_wndClassName.c_str(),         // Name of the window class
			tr_wndTitle.c_str(),             // Title of the window
			WS_CAPTION | WS_SYSMENU |        // Window style
			WS_MINIMIZEBOX,                  //
			CW_USEDEFAULT,                   // X-position of the window
			CW_USEDEFAULT,                   // Y-position of the window
			tr_cxWnd,                        // Width of the window
			tr_cyWnd,                        // Height of the window
			NULL,                            // We have no parent window, NULL
			NULL,                            // We aren't using menus, NULL
			tr_hInstance,                    // Application handle
			this);                           // Used with multiple windows, NULL
	}

	TRAINER_LIB_API STrainer::~STrainer()
	{
		
		/// Tell all cheats to turn OFF
		HANDLE hProcess = GetGameProcessHandle();
		if (hProcess)
		{
			for (unsigned int i = 0; i < d_cheats.size(); i++)
			{
				d_cheats[i]->Off(hProcess);
			}
			CloseHandle(hProcess);
		}

		// Delete cheats from memory
		for (unsigned int i = 0; i < d_cheats.size(); i++)
		{
			delete d_cheats[i];
		}

		// Delete HBRUSH made for the background of trainer if it was made
		if (tr_wndBackBmpId != -1)
			DeleteObject(hBrush);
	}


	TRAINER_LIB_API int STrainer::Run()
	{
		// Display the window on the screen
		ShowWindow(tr_hWnd, SW_SHOWNORMAL);

		// This struct holds Windows event messages
		MSG msg;

		// Wait for the next message in the queue, store the result in 'msg'
		while(GetMessage(&msg, NULL, 0, 0))
		{
			// Translate keystroke messages into the right format
			TranslateMessage(&msg);

			// Send the message to the WindowProc function
			DispatchMessage(&msg);
		}
		// Return this part of the WM_QUIT message to Windows
		return msg.wParam;
	}

	HANDLE STrainer::GetGameProcessHandle()
	{
		HWND hWnd;
		DWORD dwID;

		hWnd = FindWindow(NULL, g_title.c_str());
		if (!hWnd)
		{
			MessageBoxA(tr_hWnd, (g_title + " is not opened.").c_str(), "ERROR", 0);
			return NULL;
		}
		GetWindowThreadProcessId(hWnd, &dwID);
		return OpenProcess(PROCESS_ALL_ACCESS, NULL, dwID);
	}
}